using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Web;
using Edge.Common.ControlFlow;
using Edge.Common.Services;
using Edge.DAL.Common.SessionManagment;
using log4net;
using NHibernate;

namespace Edge.DAL.Common.SessionManagment
{
    class NHibernateModule : IHttpModule
    {
        private static readonly ILog log = LogManager.GetLogger(MethodInfo.GetCurrentMethod().DeclaringType);

        private ISessionFactory sessionFactory = null;

        private const string SESSION_KEY = "Edge.DAL.Common.SessionManagment.NHibernateModule.Session";

        void IHttpModule.Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);

        }


        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {

            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        public static ISession Session
        {
            get
            {
                HttpContext ctx = HttpContext.Current;
                if (ctx == null)
                {
                    throw new InvalidOperationException("Http context does not exists");
                    //                    return GetNonViewSession();
                }
                ISession ret = (ISession)ctx.Items[SESSION_KEY];
                if (ret == null)
                {
                    //throw new InvalidOperationException("Session not initilized in current http context");
                    Session = GetNonViewSession();
                    return Session;
                }

                return ret;
            }
            set
            {
                HttpContext ctx = HttpContext.Current;
                if (ctx == null)
                    throw new InvalidOperationException("Http context does not exists");

                if (value == null)
                    throw new ArgumentException();

                ctx.Items[SESSION_KEY] = value;

            }
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            //log.Debug("Closing single Hibernate Session in OpenSessionInViewFilter");
            try
            {
                CloseSession(Session, sessionFactory);
            }
            catch (Exception ex)
            {
                log.Error("Unexpected exception on closing Hibernate Session", ex);
            }
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            sessionFactory = Locator.GetService<ISessionFactory>();

            if (sessionFactory == null)
            {
                log.Error("session factory os not found in locator");
                return;
            }


            //log.Debug("Opening single Hibernate Session in OpenSessionInView");

            ISession nonRequestSession = (ISession)HttpContext.Current.Items[SESSION_KEY];
            if (nonRequestSession != null)
            {
                nonRequestSession.Close();
            }

            Session = GetSession(sessionFactory);
        }

        /// <summary>
        /// returned sesion for strartup application
        /// </summary>
        /// <returns></returns>
        protected static ISession GetNonViewSession()
        {
            ISession globalSession = null;

            ISessionFactory sessionFactory = Locator.GetService<ISessionFactory>();

            if (sessionFactory == null)
            {
                string message = "session factory os not found in locator for creating global session";
                log.Error(message);
                throw new ApplicationException(message);
            }

            //log.Debug("Opening Hibernate global Session");

            NHibernateModule nhibernateModule = new NHibernateModule();
            globalSession = nhibernateModule.GetSession(sessionFactory);


            Assert.CheckNotNull(globalSession);

            //log.Debug("returned global session");

            return globalSession;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sessionFactory"></param>
        /// <returns></returns>
        public virtual ISession GetSession(ISessionFactory sessionFactory)
        {
            return OpenSession(sessionFactory);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sessionFactory"></param>
        /// <returns></returns>
        protected virtual ISession OpenSession(ISessionFactory sessionFactory)
        {
            IInterceptorProvider interceptorProvider = Locator.GetService<IInterceptorProvider>();

            IInterceptor interceptor =
                interceptorProvider != null ? interceptorProvider.GetInterceptor(sessionFactory) : null;

            ISession session = interceptor != null ?
                                                       sessionFactory.OpenSession(interceptor) : sessionFactory.OpenSession();
            session.FlushMode = FlushMode.Commit;
            //           session.FlushMode = FlushMode.Never;
            return session;
        }


        protected virtual void CloseSession(ISession session, ISessionFactory sessionFactory)
        {
            ReleaseSession(session, sessionFactory);
        }

        public static void ReleaseSession(ISession session, ISessionFactory sessionFactory)
        {
            if (session == null)
            {
                return;
            }
            DoClose(session);
        }

        private static void DoClose(ISession session)
        {
            if (session != null)
            {
                //log.Debug("Closing Hibernate Session");
                try
                {
                    session.Close();
                }
                catch (HibernateException ex)
                {
                    log.Error("Could not close Hibernate Session", ex);
                }
                catch (Exception ex)
                {
                    log.Error("Unexpected exception on closing Hibernate Session", ex);
                }
            }
        }

    }
}